/**
 * @author kangkai
 * 状态机， 
 * 0，自身id
 * 2，对状态的管理（添加删除）
 * 3.运行、切换状态 
 * 4,向外部发送事件,sendFSMEvent
 * //-----------------Exp---------------
 * 	9,关于状态机，函数的定义放在主的FSM里(便于管理)，具体什么时候用是由各个状态去执行的，就是把函数的声明和使用分开处理即可
 * *10，经验就是一个fsm控制另一个fsm的生成，销毁或是状态变化的时候，要通过中介者GamePlay来通讯，
 *	这个是有用的，因为他涉及的跨fsm的调用，一个fsm请求去改变另一个fsm的状态,或控制另一个fsm对象的生成和销毁
 * 
 * 注意stateA和stateM的状态可以重复使用StateID,比如-1就通用
 * 记得如果死亡的时候是要搞掉2个状态的
 * 
1,fsm做了整理，发现其实fsm之间是可以通信的。并且好处有很多啊。
现在的结构是支持在fsmM里的fsm 去查询其他fsm状态的,但是需要保证之读而不写
fsm之间是可以查询但禁止直接操作的,fsm操作的时间要发送到总控逻辑来处理的

4,新的发现是：结构不是特别要求是最好的，保证能通信的对象都能通到信就可
 * 
 * ----------------Log----------------
 * --1207
 * 1,增加配合物理引擎使用的
 * 
 * 2，做出更通用的结构，因为实际发现fsm需要有自己的各个方法的，
 * 	之所以需要被继承，继承的fsm里可以有自己的工具函数（供自己的state使用的）,子类要有自己的各个属性，md3d,body的各个零件的3d表示和phy表示
 * 	
 * 	3,简化了结构，做除了一个更强更清洁的结构
 * 	
 * 	如果要使用物理模型，则要把b2Body.userData=md3d,
 * 	在最后更新完物理引擎后再对每个md3d设置位置
 */
package kgame5.pbe.atlantic.fsm {
	import kgame5.kutil.T;
	import kgame5.pbe.atlantic.comp.FSMBatchComp;
	import kgame5.pbe.atlantic.event.EntityMessageEvent;
	import kgame5.pbe.atlantic.event.FSMEvent;
	import kgame5.pbe.atlantic.event.GameCommandEvent;
	import kgame5.pbe.atlantic.vo.EntityMessageVO;
	import kgame5.pbe.atlantic.vo.EntityVO;
	import kgame5.pbe.engine.PBE;

	import flash.events.*;
	import flash.utils.Dictionary;

	public class FSM {
		public static const EVENT_FSM_EVENT : String = "EVENT_FSM_EVENT";//fsm对外发送了通用事件
		//	public static const 
		//		EVENTTYPE_SWITCH_STATE:String="EVENTTYPE_SWITCH_STATE";//对外发出事件
		
		//___________________Property_____________________
	
		//--状态机内部的状态,因为比如坦克有移动和攻击两个并列的状态，所以要有2个状态,这个2个状态控制同一个，又互相有影响，所以做到一个
		private  var dict_states : Dictionary = null;//状态集合

		//--状态的使用
		protected var curState : GState = null;//当前的状态

		private var id : String;

		private var entVO : EntityVO;//发送事件的时候用

		private var eventDispatcher : IEventDispatcher;//使用entity.enventDiaptcher
		
		private var master:FSMBatchComp;
		
		//____________________Method__________________

		public function FSM(id : String,vo : EntityVO,_master:FSMBatchComp) {
		
			this.id = id;
			this.entVO = vo;
		
			dict_states = new Dictionary();
			
			this.master=_master;
			
			//默认有个空状态的,状态值是-1
			addState(new GState(""));
			
			this.SwitchState("");
		}
		
		

		//引用entity.enventDiaptcher,对外发送事件用
		public function setEventDispatcher(ed : IEventDispatcher) : void {
			this.eventDispatcher = ed;
		}

//		//极少用到
//		public function dispose() : void {
//		}

		public function getID() : String {
			return id;
		}
		
		public function getMaster():FSMBatchComp{
			return master;
		}

		//----对状态的管理,添加，删除，查找-----
		public function addState(s : GState) : void {
			if(findState(s.getID()) != null) {
				throw new Error("已包含此stateID" + s.getID());
			}
			//T.p("fsm.addState",id,s.getID());
			dict_states[s.getID()] = s;
			
			s.setFSM(this);
			s.setEntityVO(entVO);
		}

		public function findState(stateID : String) : GState {
			return dict_states[stateID];
		}

		public function removeState(stateID : int) : void {
			delete dict_states[stateID];
		}

		//取得当前的状态，这个挺有用的，用来判断当前的状态
		public function getCurState() : GState {
			return curState;
		}

		//----状态的使用
		// 更新自己的状态
		public function update() : void {
			//T.p("fsm.update",id);
			if(curState != null) {
				curState.update();
			}
		}

		public function SwitchState(stateID : String,info : Object = null,followingStateParams:FollowingStateParams=null) : void {
			if(curState != null) {
				//T.p("退出State:"+curState.getID());
				curState.exit();
				curState._followingStateParams=null;
			}
			var nextState : GState = findState(stateID);
			if(nextState != null) {
				curState = nextState;
				
				curState._followingStateParams=followingStateParams;
				curState.enter(info);
				
//				//--发送事件说自己切换了状态
//				this.dispatchEvent(new KEvent(EVENTTYPE_SWITCH_STATE,stateID));
			} else {
				throw new Error("!!FSM.changeState,nextState=null " + stateID);
			}
		}

		//==============组件间通信，通知cotrollerComp有事件=====================
		//这个是被自己的子类调用的
		public function sendFSMEvent(name : String,data : Object = null) : void {
			eventDispatcher.dispatchEvent(new FSMEvent(name, data));
		}
		
		//工具函数，通知viewComp播放动画
		public function _sendEventPlayAnim(animID:String):void{
			this.sendFSMEvent(FSMEvent.NAME_PLAY_ANIM,animID);
		}
		public function _sendEventChangeDir(dir:int):void{
			this.sendFSMEvent(FSMEvent.NAME_CHANGE_DIR,dir);
		}
		public function _sendChangeForm(formID:int):void{
			this.sendFSMEvent(FSMEvent.NAME_CHANGE_FORM, formID);
		}

		

		//==============对GamePlay发送请求， message是实体之间，是平级别，command是向最高层发送=====================
		//注意这个和ControllerComp中的command是相互独立的,原因是有的entity不需要controller
		public function sendFromEntityCommand(commandName : String,data : Object = null) : void {
			eventDispatcher.dispatchEvent(new GameCommandEvent(commandName, data));
		}
		
		//调用PEB删除自己,注意只有当确认不需要外部总控器控制则删除自己时才可使用
		//非正常方式，只是快速解决问题而用，严禁滥用
		public function hack_destroySelfEntity():void{
			T.p("hack_destroySelfEntity", entVO.id);
			PBE.lookupEntity(entVO.id).destroy();//销毁鱼食,这个会通知到senseWorld的
		}
		
		//==============实体间发消息，比如一条鱼通知另一条鱼来吃食======
		public function sendEntityToEntityMessage(msgName : String,toID : String,scope : int=1,data : *=null) : void {
			//T.p("sendEntityToEntityMessage",msgName,toID);
			var mvo : EntityMessageVO = new EntityMessageVO(msgName, data, entVO, scope,toID);
			PBE.senseWorld.sendEntityToEntityMessage(mvo);
			//eventDispatcher.dispatchEvent(new EntityMessageEvent(EntityMessageEvent.TYPE, mvo));
		}
	}//end of class
}

//	//设置到各个state里的ISceneWorld
//	public function setSenceWorld(senceWorld:ISenceWorld):void{
//		for each(var state:GState in dict_states){
//			state.setSenceWorld(senceWorld);
//		}
//	}
//	//当Entity被添加到世界后，被world调用，传入
//	public function setSpacialManager(spacialManager:SpacialManager):void{
//		for each(var state:GState in dict_states){
//			state.setSpacialManager(spacialManager);
//		}
//	}
	
//	public function setVO(p_vo:EntityVO):void{
//		this._vo=p_vo;
//	}
//	
//	public function setHardVO(hardVO:HardVO):void{
//		this._hardVO=hardVO;
//	}